#include <jni.h>
#include <string>

#include <stdlib.h>
#include <android/log.h>

#include <stdio.h>
#include "abstypes.h"
#include "BeautyShot_Image_Algorithm.h"
#include "BeautyShot_Video_Algorithm.h"

#define MOK 0
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,"TEST",__VA_ARGS__)

const static int32_t w = 640;
const static int32_t h = 480;

const static int32_t level = 90;

MVoid processImage(MTChar *pFilename, MInt32 iWidth, MInt32 iHeight,int feature);
MVoid processVideo(MTChar *pFilename, MInt32 iWidth, MInt32 iHeight,int feature);
MLong GetCurrentTime();

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_szl7033_jni_1cpp_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";

    //MTChar pFilename[] = "/storage/emulated/0/DCIM/Camera/img8M_2448x3264.yuyv";
    MTChar pFilename[256] = {};
    //sprintf(pFilename,"/sdcard/a_b1_%dx%d.nv21",w,h);
    sprintf(pFilename,"/sdcard/b1_%dx%d.nv21",w,h); //未处理

    //FACE_SOFTEN
    //processImage(pFilename, w, h ,1);
    //EYE_ENLARGEMENT
    //processImage(pFilename, w, h ,4);
    //FACE_SLENDER
    //processImage(pFilename, w, h ,5);
    //SKIN_TONE_BRIGHT
    //processImage(pFilename, w, h ,51);
    //ALL
    //processImage(pFilename, w, h ,61);

    //FACE_SOFTEN
    processVideo(pFilename,w,h,1);


    return env->NewStringUTF(hello.c_str());
}

MVoid setOffScreen(ASVLOFFSCREEN *pImg, MUInt8 *pData, MInt32 iWidth, MInt32 iHeight)
{
	pImg->u32PixelArrayFormat = ASVL_PAF_NV21;
	pImg->i32Width = iWidth;
	pImg->i32Height = iHeight;
	pImg->pi32Pitch[0] = iWidth;
	pImg->pi32Pitch[1] = iWidth;
	pImg->ppu8Plane[0] = pData;
	pImg->ppu8Plane[1] = pData + iWidth*iHeight;
}

/*
MVoid setOffScreen(ASVLOFFSCREEN *pImg, MUInt8 *pData,
                   MInt32 iWidth, MInt32 iHeight)
{
    pImg->u32PixelArrayFormat = ASVL_PAF_YUYV;
    pImg->i32Width = iWidth;
    pImg->i32Height = iHeight;
    pImg->pi32Pitch[0] = 2*iWidth;
    pImg->pi32Pitch[1] = MNull;
    pImg->pi32Pitch[2] = MNull;
    pImg->ppu8Plane[0] = pData;
    pImg->ppu8Plane[1] = MNull;
    pImg->ppu8Plane[2] = MNull;
}
*/

MVoid processImage(MTChar *pFilename, MInt32 iWidth, MInt32 iHeight,int feature)
{
	MLong t1,t2,t3,t4;

	t1 = GetCurrentTime();  //开始处理时间点

	BeautyShot_Image_Algorithm*		m_BeautyShot_Image_Algorithm = MNull;

	if(Create_BeautyShot_Image_Algorithm(BeautyShot_Image_Algorithm::CLASSID,
				&m_BeautyShot_Image_Algorithm)!= MOK ||
				m_BeautyShot_Image_Algorithm == nullptr){
		LOGD("Create_BeautyShot_Image_Algorithm, fail");
		return;
	}

	MRESULT ret = m_BeautyShot_Image_Algorithm->Init();
	if (ret != MOK)
		return;

    ASVLOFFSCREEN	tScreenSrc = {0};
    LPASVLOFFSCREEN	pScreenDst;

    //LOGD("T2");
	MInt32	iFrameLength = iWidth*iHeight*3/2;
	MUInt8 *pData = (MUInt8 *)malloc(iFrameLength*sizeof(MUInt8));
	FILE	*stream = fopen(pFilename, "re");

	//打开对应文件追加流
	FILE *fp = nullptr;

	while (fread(pData, 1, iFrameLength, stream) == iFrameLength)
	{
		setOffScreen(&tScreenSrc, pData, iWidth, iHeight);
		pScreenDst = &tScreenSrc;

		//set parameters
		switch(feature) {
                case 1:
                    LOGD("FACE SOFTEN");
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_FACE_SOFTEN_KEY ,level);
                    sprintf(pFilename,"/sdcard/FEATURE_FACE_SOFTEN_%dx%d.nv21",w,h);
                    fp = fopen(pFilename, "abe");
                    break;
                case 4:
                    LOGD("EYE ENLARGEMENT");
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_EYE_ENLARGEMENT_KEY  ,level);
                    sprintf(pFilename,"/sdcard/FEATURE_EYE_ENLARGEMENT_%dx%d.nv21",w,h);
                    fp = fopen(pFilename, "abe");
                    break;
                case 5:
                    LOGD("FACE SLENDER");
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_FACE_SLENDER_KEY  ,level);
                    sprintf(pFilename,"/sdcard/FEATURE_FACE_SLENDER_%dx%d.nv21",w,h);
                    fp = fopen(pFilename, "abe");
                    break;
                case 51:
                    LOGD("SKIN TONE BRIGHT");
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_SKIN_TONE_BRIGHT_KEY  ,level);
                    sprintf(pFilename,"/sdcard/FEATURE_SKIN_TONE_BRIGHT_%dx%d.nv21",w,h);
                    fp = fopen(pFilename, "abe");
                    break;
                case 61:
                    LOGD("ALL");
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_FACE_SOFTEN_KEY ,level);
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_EYE_ENLARGEMENT_KEY  ,level);
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_FACE_SLENDER_KEY  ,level);
                    m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_SKIN_TONE_BRIGHT_KEY  ,level);
                    sprintf(pFilename,"/sdcard/FEATURE_ALL_%dx%d.nv21",w,h);
                    fp = fopen(pFilename, "abe");
                    break;
                default:
                    LOGD("WRONG PARAM");
                    break;
        }
        //LOGD("帧数");
		//set other features level

        /*
		ABS_TColorArray colorarray;
		MMemSet(&colorarray, 0, sizeof(ABS_TColorArray));
		colorarray.lColorNum =1;
		colorarray.pColors[0]=0xff0000;
		m_BeautyShot_Image_Algorithm->SetFeatureLevel(FEATURE_BLUSH_KEY,30);
		m_BeautyShot_Image_Algorithm->SetColorArray(FEATURE_BLUSH_KEY,&colorarray);
        */

		//do process
		t2 = GetCurrentTime();  //开始单帧处理时间点

		ret = m_BeautyShot_Image_Algorithm->Process(&tScreenSrc,pScreenDst,MNull,MNull);

        t3 = GetCurrentTime();  //结束单帧处理时间点

        LOGD("====单帧处理时间：%ld ms;",t3-t2);

		if (ret != MOK)
		{
		    LOGD("ret != MOK");
		}
        else LOGD("处理成功");

		////////////////////////////////////////////////////////////////
	    if (nullptr != fp)
        {
            fwrite((MUInt8*)pData, iFrameLength, 1, fp);
            LOGD("write succeed");
            fclose(fp);
        }
        else LOGD("face soften fail");
		/////////////////////////////////////////////////////////////////
	}


    free(pData);
    fclose(fp);
	fclose(stream);
	m_BeautyShot_Image_Algorithm->UnInit();
	m_BeautyShot_Image_Algorithm->Release();
	m_BeautyShot_Image_Algorithm = nullptr;

	t4 = GetCurrentTime();  //结束处理时间点

	LOGD("====处理时间：%ld ms;",t4-t1);
}

MVoid processVideo(MTChar *pFilename, MInt32 iWidth, MInt32 iHeight,int feature)
{
    MLong t1,t2,t3,t4;

    t1 = GetCurrentTime();  //开始处理时间点

    BeautyShot_Video_Algorithm* m_BeautyShot_Video_Algorithm = MNull;

    if(Create_BeautyShot_Video_Algorithm(BeautyShot_Video_Algorithm::CLASSID,
                                         &m_BeautyShot_Video_Algorithm)!= MOK ||
       m_BeautyShot_Video_Algorithm == nullptr){
        LOGD("Create_BeautyShot_Video_Algorithm, fail");
        return;
    }

    MRESULT ret = m_BeautyShot_Video_Algorithm->Init();
    if (ret != MOK)
        return;

    ASVLOFFSCREEN tScreenSrc = {0};
    LPASVLOFFSCREEN pScreenDst;

    //LOGD("T2");
    MInt32	iFrameLength = iWidth*iHeight*3/2;
    MUInt8 *pData = (MUInt8 *)malloc(iFrameLength*sizeof(MUInt8));
    FILE	*stream = fopen(pFilename, "re");

    //打开对应文件追加流
    FILE *fp = nullptr;

    while (fread(pData, 1, iFrameLength, stream) == iFrameLength)
    {
        setOffScreen(&tScreenSrc, pData, iWidth, iHeight);
        pScreenDst = &tScreenSrc;

        //set parameters
        switch(feature) {
            case 1:
                LOGD("FACE SOFTEN");
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_FACE_SOFTEN_KEY ,level);
                sprintf(pFilename,"/sdcard/FEATURE_FACE_SOFTEN_%dx%d.nv21",w,h);
                fp = fopen(pFilename, "abe");
                break;
            case 4:
                LOGD("EYE ENLARGEMENT");
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_EYE_ENLARGEMENT_KEY  ,level);
                sprintf(pFilename,"/sdcard/FEATURE_EYE_ENLARGEMENT_%dx%d.nv21",w,h);
                fp = fopen(pFilename, "abe");
                break;
            case 5:
                LOGD("FACE SLENDER");
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_FACE_SLENDER_KEY  ,level);
                sprintf(pFilename,"/sdcard/FEATURE_FACE_SLENDER_%dx%d.nv21",w,h);
                fp = fopen(pFilename, "abe");
                break;
            case 51:
                LOGD("SKIN TONE BRIGHT");
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_SKIN_TONE_BRIGHT_KEY  ,level);
                sprintf(pFilename,"/sdcard/FEATURE_SKIN_TONE_BRIGHT_%dx%d.nv21",w,h);
                fp = fopen(pFilename, "abe");
                break;
            case 61:
                LOGD("ALL");
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_FACE_SOFTEN_KEY ,level);
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_EYE_ENLARGEMENT_KEY  ,level);
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_FACE_SLENDER_KEY  ,level);
                m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_SKIN_TONE_BRIGHT_KEY  ,level);
                sprintf(pFilename,"/sdcard/FEATURE_ALL_%dx%d.nv21",w,h);
                fp = fopen(pFilename, "abe");
                break;
            default:
                LOGD("WRONG PARAM");
                break;
        }
        //LOGD("帧数");
        //set other features level

        /*
		ABS_TColorArray colorarray;
		MMemSet(&colorarray, 0, sizeof(ABS_TColorArray));
		colorarray.lColorNum =1;
		colorarray.pColors[0]=0xff0000;
		m_BeautyShot_Video_Algorithm->SetFeatureLevel(FEATURE_BLUSH_KEY,30);
		m_BeautyShot_Video_Algorithm->SetColorArray(FEATURE_BLUSH_KEY,&colorarray);
        */

        //do process
        t2 = GetCurrentTime();  //开始单帧处理时间点

        ret = m_BeautyShot_Video_Algorithm->Process(&tScreenSrc,pScreenDst,MNull,MNull);

        t3 = GetCurrentTime();  //结束单帧处理时间点

        LOGD("====单帧处理时间：%ld ms;",t3-t2);

        if (ret != MOK)
        {
            LOGD("ret != MOK");
        }
        else LOGD("处理成功");

        ////////////////////////////////////////////////////////////////
        if (nullptr != fp)
        {
            fwrite(pData, iFrameLength, 1, fp);
            LOGD("write succeed");
            fclose(fp);
        }
        else LOGD("face soften fail");
        /////////////////////////////////////////////////////////////////
    }

    free(pData);
    fclose(fp);
    fclose(stream);
    m_BeautyShot_Video_Algorithm->UnInit();
    m_BeautyShot_Video_Algorithm->Release();
    m_BeautyShot_Video_Algorithm = nullptr;

    t4 = GetCurrentTime();  //结束处理时间点

    LOGD("====处理时间：%ld ms;",t4-t1);
}


MLong GetCurrentTime()
{
    struct timeval tv;
    gettimeofday(&tv, nullptr);
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
